package com.sheledon.flyCat.core.aop.intercept;

import com.sheledon.flyCat.annotation.aop.After;
import com.sheledon.flyCat.annotation.aop.Before;
import com.sheledon.flyCat.annotation.aop.PointCut;
import com.sheledon.flyCat.common.utils.ReflectionUtils;
import com.sheledon.flyCat.core.aop.lang.JoinPoint;
import com.sheledon.flyCat.core.aop.lang.JoinPointImpl;
import com.sheledon.flyCat.core.aop.utils.PatternUtils;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

/**
 * 这里打算使用正则表达式来替代 pointcut 表达式
 * @author sheledon
 */
public class AspectInterceptor extends Interceptor{
    private final Object aspectBean;
    private List<Method> beforeAction = new ArrayList<>();
    private List<Method> afterAction = new ArrayList<>();
    private HashSet<String> interceptExps = new HashSet<>();

    @Override
    public boolean supports(Object bean) {
        String matcher = bean.getClass().getName();
        return interceptExps
                .stream()
                .anyMatch(exps-> PatternUtils.simpleMatch(exps,matcher))
                && (beforeAction.size()>0 || afterAction.size()>0);
    }

    public AspectInterceptor(Object bean) {
        this.aspectBean = bean;
        init();
    }

    public void init(){
        HashSet<String> finalExps = new HashSet<>();
        Class<?> aClass = aspectBean.getClass();
        for (Method method : aClass.getDeclaredMethods()) {
            method.setAccessible(true);
            PointCut pointCut = method.getAnnotation(PointCut.class);
            if (pointCut!=null){
                finalExps.add(pointCut.value());
            }
            Before before = method.getAnnotation(Before.class);
            if (before!=null){
                beforeAction.add(method);
            }
            After after = method.getAnnotation(After.class);
            if (after != null) {
                afterAction.add(method);
            }
        }
        finalExps.forEach(exp->{
            String tmp = exp.replaceAll("[.]","\\\\.");
            interceptExps.add(tmp.replaceAll("[*]",".+?"));
        });
    }

    @Override
    public Object intercept(MethodInvocation methodInvocation) {
        JoinPoint joinPoint = new JoinPointImpl(aspectBean,
                methodInvocation.getArgs(), methodInvocation.getTarget());
        beforeAction.forEach(method->{
            ReflectionUtils.executeMethod(method, aspectBean,new Object[]{joinPoint});
        });
        Object result = methodInvocation.proceed();
        afterAction.forEach(method -> {
            ReflectionUtils.executeMethod(method, aspectBean,new Object[]{joinPoint});
        });
        return result;
    }
}
